package cn.blnp.net.flowable.task.ext.decision;

import cn.hutool.core.map.MapUtil;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <h3>决策任务整合案例</h3>
 *
 * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
 * @version 1.0
 * @since 2025/5/19 11:51
 */
@Slf4j
@SpringBootTest
public class DecisionTaskTest {

    @Resource
    private RepositoryService repositoryService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private TaskService taskService;
    @Resource
    private HistoryService historyService;

    /**
     *  <h2>决策表</h2>
     *  <p>
     *  &emsp;&emsp;决策表是一种用于描述和表示决策规则的工具，适用于描述处理判断条件较多，各条件又相互组合、有多种决策方案的情况。决策表是一组相关输入（input）和输出（output）表达式的表格表示形式，
     *  被组织成规则（rule），这些规则指示哪个输出条目适用于一组特定的输入条目，一个完整的表包含输入值（所有规则）的所有可能组合，可以清晰地展示所有可能的情况和对应的决策结果，从而精确而简洁地描述复杂逻辑。
     *  &emsp;&emsp;决策表可以通过决策表设计器来创建。Flowable UI内置了决策表设计器，单击“决策表”标签，跳转到决策表管理页面，单击“创建决策表”按钮，在弹出的对话框里输入决策表名称、决策表key和描述后，单击
     *  “创建新的决策”按钮即可跳转到决策表设计器页面。它由一个表格组成，表格的每一行代表一个可能的情况或条件，每一列代表一个可能的决策结果或动作。在表格中，可以使用符号或者文字来表示条件和动作，以及它们之
     *  间的关系。
     *  </p>
     **/
    @Test
    public void test() {

    }


    /**
     *  <h2>决策表任务整合案例</h2>
     *  <hr/>
     *  <p>
     *      以下是一个商品打折的整合案例。
     *      <b>流程定义文件：</b>{@link flow/decisionTaskProcess.bpmn20.xml}<br/>
     *      <b>流程预览图：</b><br/>
     *      <img src="https://cdn4.winhlb.com/2025/05/19/682ac80b6aaaf.png" /><br/>
     *      <b>决策表配置文件：</b>{@link dmn/discountCalculationDecision.dmn}<br/>
     *      <b>决策表预览图：</b><br/>
     *      <img src="https://cdn4.winhlb.com/2025/05/19/682acfefd8cc3.png" /><br/>
     *      这个决策表一共有4列，分别是一列输入（消费金额）、两列输出（折扣价格和折扣率）和一列备注。决策表一共有3行，分别对应流程需求的3个条件。每一行的第一列表示输入条件，这里配置的是使用流程变量
     *      originalTotalPrice的判断表达式，第二列和第三列表示对应的输出结果。Hit Policy选择表示规则匹配策略：
     *      <img src="https://cdn4.winhlb.com/2025/05/19/682ad3d81f38b.png" /><br/>
     *  </p>
     **/
    @Test
    public void testExample() {
        /**
         *  注意事项：
         *  1、使用决策任务元素时，需要引用指定具体的决策表
         *  2、使用决策表需要引用flowable的相关依赖并配置启用 dmn 模块
         **/
        Deployment deploy = repositoryService.createDeployment()
                .name("决策任务案例流程")
                .addClasspathResource("flow/decisionTaskProcess.bpmn20.xml")
                .addClasspathResource("dmn/discountCalculationDecision.dmn")
                .deploy();
        log.info("部署流程定义：{}", deploy.getId());
        ProcessDefinition procDef = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploy.getId())
                .singleResult();
        log.info("流程定义编号：{}", procDef.getId());
        //启动流程实例
        ProcessInstance procInst = runtimeService.startProcessInstanceById(procDef.getId());
        TaskQuery taskQuery = taskService.createTaskQuery()
                .processInstanceId(procInst.getId());

        //首个任务查询
        Task task = taskQuery.singleResult();
        //设置流程变量
        Map<String, Object> varMap = MapUtil.builder(new HashMap<String, Object>())
                .put("originalTotalPrice", 6666)
                .build();
        //办理第一个任务
        taskService.complete(task.getId(), varMap);
        //查询并打印流程变量
        List<HistoricVariableInstance> hisVariables = historyService
                .createHistoricVariableInstanceQuery()
                .processInstanceId(procInst.getId()).list();
        hisVariables.stream().forEach(hisVariable -> log.info("流程变量名：{}，变量值：{}",
                hisVariable.getVariableName(), hisVariable.getValue()));

        /**
         *  演示结果：
         *  2025-05-19 14:14:18.504  INFO 60240 --- [           main] c.b.n.f.t.ext.decision.DecisionTaskTest  : 部署流程定义：7f0c2f02-3478-11f0-8a82-50ebf6ec8f6d
         * 2025-05-19 14:14:18.507  INFO 60240 --- [           main] c.b.n.f.t.ext.decision.DecisionTaskTest  : 流程定义编号：decisionTaskProcess:2:7f498626-3478-11f0-8a82-50ebf6ec8f6d
         * 2025-05-19 14:14:18.747  INFO 60240 --- [           main] c.b.n.f.t.e.d.Deduction2JavaDelegate     : 折扣前消费金额：6666，折扣率：0.9，折扣后实际消费金额：5999.400000000001
         * 2025-05-19 14:14:18.815  INFO 60240 --- [           main] c.b.n.f.t.ext.decision.DecisionTaskTest  : 流程变量名：originalTotalPrice，变量值：6666
         * 2025-05-19 14:14:18.815  INFO 60240 --- [           main] c.b.n.f.t.ext.decision.DecisionTaskTest  : 流程变量名：actualTotalPrice，变量值：5999.400000000001
         * 2025-05-19 14:14:18.815  INFO 60240 --- [           main] c.b.n.f.t.ext.decision.DecisionTaskTest  : 流程变量名：discountRatio，变量值：0.9
         **/
    }
}
